package com.meiyuetao.myt.purchase.service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import lab.s2jh.bpm.service.ActivitiService;
import lab.s2jh.core.dao.BaseDao;
import lab.s2jh.core.service.BaseService;
import lab.s2jh.core.service.Validation;
import lab.s2jh.core.util.DateUtils;
import lab.s2jh.ctx.DynamicConfigService;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.google.common.collect.Lists;
import com.meiyuetao.myt.core.constant.StorageModeEnum;
import com.meiyuetao.myt.core.constant.VoucherStateEnum;
import com.meiyuetao.myt.core.constant.VoucherTypeEnum;
import com.meiyuetao.myt.finance.dao.BizTradeUnitDao;
import com.meiyuetao.myt.finance.entity.AccountInOut;
import com.meiyuetao.myt.finance.service.AccountInOutService;
import com.meiyuetao.myt.job.BusinessNotifyService;
import com.meiyuetao.myt.md.dao.CommodityDao;
import com.meiyuetao.myt.md.dao.CommodityVaryPriceDao;
import com.meiyuetao.myt.md.entity.Commodity;
import com.meiyuetao.myt.md.entity.CommodityVaryPrice;
import com.meiyuetao.myt.purchase.dao.PurchaseOrderDetailDao;
import com.meiyuetao.myt.purchase.dao.PurchaseReceiptDao;
import com.meiyuetao.myt.purchase.dao.PurchaseReceiptDetailDao;
import com.meiyuetao.myt.purchase.entity.PurchaseOrder;
import com.meiyuetao.myt.purchase.entity.PurchaseOrderDetail;
import com.meiyuetao.myt.purchase.entity.PurchaseReceipt;
import com.meiyuetao.myt.purchase.entity.PurchaseReceiptDetail;
import com.meiyuetao.myt.stock.dao.CommodityStockMoveDetailDao;
import com.meiyuetao.myt.stock.dao.StorageLocationDao;
import com.meiyuetao.myt.stock.entity.CommodityStock;
import com.meiyuetao.myt.stock.entity.CommodityStockMoveDetail;
import com.meiyuetao.myt.stock.entity.StockInOut;
import com.meiyuetao.myt.stock.entity.StorageLocation;
import com.meiyuetao.myt.stock.service.CommodityStockService;
import com.meiyuetao.myt.stock.service.StockInOutService;

@Service
@Transactional
public class PurchaseReceiptService extends BaseService<PurchaseReceipt, Long> {

    @Autowired
    private PurchaseReceiptDao purchaseReceiptDao;
    @Autowired
    private CommodityDao commodityDao;
    @Autowired
    private CommodityStockService commodityStockService;
    @Autowired
    private StorageLocationDao storageLocationDao;
    @Autowired
    private PurchaseReceiptDetailDao purchaseReceiptDetailDao;
    @Autowired
    private DynamicConfigService dynamicConfigService;
    @Autowired
    private BusinessNotifyService businessNotifyService;

    @Autowired
    private AccountInOutService accountInOutService;
    @Autowired
    private BizTradeUnitDao bizTradeUnitDao;
    @Autowired
    private StockInOutService stockInOutService;
    @Autowired
    private CommodityStockMoveDetailDao commodityStockMoveDetailDao;
    @Autowired
    private PurchaseOrderDetailDao purchaseOrderDetailDao;
    @Autowired
    private CommodityVaryPriceDao commodityVaryPriceDao;
    @Autowired(required = false)
    private ActivitiService activitiService;
    @Autowired
    private PurchaseOrderService purchaseOrderService;

    @Override
    protected BaseDao<PurchaseReceipt, Long> getEntityDao() {
        return purchaseReceiptDao;
    }

    private AccountInOut buildDefaultAccountInOut(PurchaseReceipt entity) {
        AccountInOut accountInOut = new AccountInOut();
        accountInOut.setVoucher(entity.getVoucher());
        accountInOut.setVoucherType(VoucherTypeEnum.JH);
        accountInOut.setPostingDate(entity.getVoucherDate());
        return accountInOut;
    }

    @Override
    public PurchaseReceipt save(PurchaseReceipt entity) {
        Assert.isTrue(entity.getRedwordDate() == null);

        List<AccountInOut> accountInOuts = Lists.newArrayList();
        // BigDecimal totalTaxAmount = entity.getTotalTaxAmount();
        BigDecimal costAmount = entity.getTotalCostAmount();
        BigDecimal totalCostAmount = entity.getTotalCostAmount();
        /*
         * if (totalTaxAmount != null && totalTaxAmount.floatValue() != 0) {
         * //借：222102=进项税额 AccountInOut accountInOut =
         * buildDefaultAccountInOut(entity);
         * accountInOut.setAccountSubjectCode("222102");
         * accountInOut.setAccountSummary("采购进项税额");
         * accountInOut.setAmount(totalTaxAmount);
         * accountInOut.setAccountDirection(true);
         * accountInOuts.add(accountInOut);
         * 
         * //总金额加上应缴税费 costAmount = totalCostAmount.add(totalTaxAmount); }
         * //借：库存商品
         *//*
            * AccountInOut accountInOut2 = buildDefaultAccountInOut(entity);
            * accountInOut2.setAccountSubjectCode("1406");
            * accountInOut2.setAccountSummary("采购入库库存商品");
            * accountInOut2.setAmount(totalCostAmount);
            * accountInOut2.setAccountDirection(true);
            * accountInOuts.add(accountInOut2);
            * 
            * //已付账款 BigDecimal payedAmount = entity.getPayedAmount();
            * BigDecimal toPayAmount = costAmount; if (payedAmount != null &&
            * payedAmount.floatValue() != 0) {
            * Validation.isTrue(payedAmount.compareTo(costAmount) <= 0,
            * "付款金额不能大于应付金额");
            * 
            * AccountInOut accountInOut3 = buildDefaultAccountInOut(entity);
            * accountInOut3.setAccountSubject(entity.getAccountSubject());
            * accountInOut3.setAccountSummary("采购付款");
            * accountInOut3.setAmount(payedAmount);
            * accountInOut3.setAccountDirection(false);
            * accountInOuts.add(accountInOut3);
            * 
            * toPayAmount = toPayAmount.subtract(payedAmount); } //应付账款 if
            * (toPayAmount.doubleValue() > 0) { //贷：2202=应付账款 AccountInOut
            * accountInOut4 = buildDefaultAccountInOut(entity);
            * accountInOut4.setAccountSubjectCode("2202");
            * accountInOut4.setAccountSummary("采购应付账款");
            * accountInOut4.setAmount(toPayAmount);
            * accountInOut4.setBizTradeUnit
            * (bizTradeUnitDao.findOne(entity.getSupplier
            * ().getBizTradeUnitId()));
            * accountInOut4.setAccountDirection(false);
            * accountInOuts.add(accountInOut4); }
            * accountInOutService.saveBalance(accountInOuts);
            */

        for (PurchaseReceiptDetail item : entity.getPurchaseReceiptDetails()) {
            item.setPurchaseReceipt(entity);
            // 如果留空并且设置了过期日期，会自动以过期日期的年月YYYYMM格式作为批次号
            if (StringUtils.isBlank(item.getBatchNo()) && item.getExpireDate() != null) {
                item.setBatchNo(DateUtils.formatDate(item.getExpireDate(), DateUtils.FORMAT_YYYYMM));
            }
            Commodity commodity = commodityDao.findOne(item.getCommodity().getId());
            StorageLocation storageLocation = storageLocationDao.findOne(item.getStorageLocation().getId());
            CommodityStock commodityStock = commodityStockService.findBy(commodity, storageLocation, item.getBatchNo());
            if (commodityStock == null) {
                commodityStock = new CommodityStock();
                commodityStock.setCommodity(commodity);
                commodityStock.setStorageLocation(storageLocation);
                commodityStock.setBatchNo(item.getBatchNo());
                commodityStock.setExpireDate(item.getExpireDate());
            }
            // 第一次采购，如果库存成本价为0，则用采购价覆盖库存成本价
            if (commodityStock.getCostPrice().equals(BigDecimal.ZERO)) {
                commodityStock.setCostPrice(item.getCostPrice());
            } else {
                // 以绝对值处理数量为负数的情况
                BigDecimal costAmountItem = item.getQuantity().multiply(item.getCostPrice());
                BigDecimal absExistStockQuantity = commodityStock.getCurStockQuantity().abs().add(item.getQuantity());
                BigDecimal absExistStockAmount = commodityStock.getCurStockAmount().abs().add(costAmountItem);

                if (!absExistStockQuantity.equals(BigDecimal.ZERO.setScale(2, BigDecimal.ROUND_HALF_DOWN))) {
                    commodityStock.setCostPrice(absExistStockAmount.divide(absExistStockQuantity, 2, BigDecimal.ROUND_HALF_EVEN));
                } else {
                    commodityStock.setCostPrice(BigDecimal.ZERO);
                }
            }

            StockInOut stockInOut = new StockInOut(entity.getVoucher(), item.getSubVoucher(), VoucherTypeEnum.JH, commodityStock);
            stockInOut.setDiffQuantity(item.getQuantity());
            stockInOut.setDiffStockAmount(item.getCostAmount());
            stockInOut.setOperationSummary("采购入库增加实际库存量");

            // 如果从调货单选取，更新到货单行项已收获量
            if (item.getCommodityStockMoveDetail() != null && item.getCommodityStockMoveDetail().getId() != null) {

                CommodityStockMoveDetail commodityStockMoveDetail = commodityStockMoveDetailDao.findOne(item.getCommodityStockMoveDetail().getId());
                commodityStockMoveDetail.setInStockQuantity(commodityStockMoveDetail.getInStockQuantity().add(item.getQuantity()));
                commodityStockMoveDetailDao.save(commodityStockMoveDetail);

                stockInOut.setDiffPurchasingQuantity(item.getQuantity().negate());
                stockInOut.addOperationSummary("采购入库扣减调货单累加的在途量");
            }

            // 关联采购订单的处理
            if (item.getPurchaseOrderDetail() != null && item.getPurchaseOrderDetail().getId() != null) {

                PurchaseOrderDetail purchaseOrderDetail = purchaseOrderDetailDao.findOne(item.getPurchaseOrderDetail().getId());
                BigDecimal canRecvQuantity = purchaseOrderDetail.getQuantity().subtract(purchaseOrderDetail.getRecvQuantity());
                Validation.isTrue(item.getQuantity().compareTo(canRecvQuantity) <= 0, "商品：" + commodity.getDisplay() + "数量:" + item.getQuantity() + "不能大于采购订单未收货的数量:"
                        + purchaseOrderDetail.getQuantity().subtract(purchaseOrderDetail.getRecvQuantity()));
                Validation.isTrue(item.getAmount().compareTo(purchaseOrderDetail.getAmount()) <= 0, "商品：" + commodity.getDisplay() + "折后金额" + item.getAmount() + "不能大于采购订单折后金额:"
                        + purchaseOrderDetail.getAmount());
                // 更新采购订单行项"已收货量"
                purchaseOrderDetail.setRecvQuantity(purchaseOrderDetail.getRecvQuantity().add(item.getQuantity()));
                purchaseOrderDetailDao.save(purchaseOrderDetail);
                // 采购收货时候有无批次号，均会去扣减无批次号的在途量
                PurchaseOrder purchaseOrder = purchaseOrderDetail.getPurchaseOrder();
                // 德国库模式，不录入物流，没有在途量
                if (!StorageModeEnum.AUTO.equals(purchaseOrder.getStorageMode())) {
                    CommodityStock podCommodityStock = commodityStockService.findBy(purchaseOrderDetail.getCommodity(), purchaseOrderDetail.getStorageLocation());
                    StockInOut podStockInOut = new StockInOut(entity.getVoucher(), item.getSubVoucher(), VoucherTypeEnum.JH, podCommodityStock);
                    podStockInOut.setDiffPurchasingQuantity(item.getQuantity().negate());
                    podStockInOut.addOperationSummary("采购入库扣减采购订单累加的在途量");
                    stockInOutService.saveCascade(podStockInOut);
                }
            }

            stockInOutService.saveCascade(stockInOut);

            // TODO
            // 税等保持会计信息

            // 同步CommodityVaryPrice的lastPurchasePrice（最近采购价格）
            CommodityVaryPrice commodityVaryPrice = commodity.getCommodityVaryPrice();
            if (!item.getCostPrice().equals(commodityVaryPrice.getLastPurchasePrice())) {
                commodityVaryPrice.setLastPurchasePrice(item.getCostPrice());
                commodityVaryPriceDao.save(commodityVaryPrice);
            }
            if (StringUtils.isBlank(commodity.getMeasureUnit()) && StringUtils.isNotBlank(item.getMeasureUnit())) {
                commodity.setMeasureUnit(item.getMeasureUnit());
                commodityDao.save(commodity);
            }

        }
        purchaseReceiptDao.save(entity);
        // 收货入库通知邮件
        // businessNotifyService.sendPurchaseReceiptEmail(entity);

        /*
         * Set<PurchaseOrder> purchaseOrders = new HashSet<PurchaseOrder>();
         * //查找采购单关联的采购订单 for (PurchaseReceiptDetail prd :
         * entity.getPurchaseReceiptDetails()) { if
         * (prd.getPurchaseOrderDetail() != null) { PurchaseOrderDetail
         * purchaseOrderDetail =
         * purchaseOrderDetailDao.findOne(prd.getPurchaseOrderDetail()
         * .getId());
         * purchaseOrders.add(purchaseOrderDetail.getPurchaseOrder()); } }
         * //遍历采购订单，找出全部收货完成的采购订单 for (PurchaseOrder purchaseOrder :
         * purchaseOrders) { Boolean isFinished = true; for (PurchaseOrderDetail
         * pod : purchaseOrder.getPurchaseOrderDetails()) { if
         * (pod.getRecvQuantity().compareTo(pod.getQuantity()) < 0) { isFinished
         * = false; break; } } if (isFinished) {
         * activitiService.deleteProcessInstanceByEntity(purchaseOrder); } }
         */
        return entity;
    }

    public void chargeAgainst(PurchaseReceipt entity) {
        PurchaseReceipt purchaseReceipt = new PurchaseReceipt();
        entity.setVoucherState(VoucherStateEnum.REDW);
        entity.setLastOperationSummary(entity.buildLastOperationSummary("红冲"));
        purchaseReceiptDao.save(entity);

        String[] copyIgnoreProperties = ArrayUtils.addAll(entity.retriveCommonProperties(), new String[] { "purchaseReceiptDetails", "voucher", "voucherDate" });
        BeanUtils.copyProperties(entity, purchaseReceipt, copyIgnoreProperties);
        purchaseReceipt.setVoucherDate(new Date());
        purchaseReceipt.setVoucher("R" + entity.getVoucher());

        stockInOutService.redword(entity.getVoucher(), VoucherTypeEnum.JH, purchaseReceipt.getVoucher());

        for (PurchaseReceiptDetail item : entity.getPurchaseReceiptDetails()) {
            // 如果从调货单选取，退回更新到货单行项已收获量
            if (item.getCommodityStockMoveDetail() != null && item.getCommodityStockMoveDetail().getId() != null) {
                CommodityStockMoveDetail commodityStockMoveDetail = commodityStockMoveDetailDao.findOne(item.getCommodityStockMoveDetail().getId());
                commodityStockMoveDetail.setInStockQuantity(commodityStockMoveDetail.getInStockQuantity().subtract(item.getQuantity()));
                commodityStockMoveDetailDao.save(commodityStockMoveDetail);
            }

            // 关联采购订单的处理, 退回更新采购订单行项"已收货量"
            if (item.getPurchaseOrderDetail() != null && item.getPurchaseOrderDetail().getId() != null) {
                PurchaseOrderDetail purchaseOrderDetail = purchaseOrderDetailDao.findOne(item.getPurchaseOrderDetail().getId());
                purchaseOrderDetail.setRecvQuantity(purchaseOrderDetail.getRecvQuantity().subtract(item.getQuantity()));
                purchaseOrderDetailDao.save(purchaseOrderDetail);
            }
        }

        accountInOutService.redword(entity.getVoucher(), VoucherTypeEnum.JH, purchaseReceipt.getVoucher());
    }

    public void bpmReceipt(PurchaseOrder purchaseOrder, String taskId, PurchaseReceipt entity) {
        this.save(entity);
        purchaseOrderService.bpmUpdate(purchaseOrder, taskId, null);

    }
}
